package com.thoughtworks.studio.tools.cardkit;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jhotdraw.app.Application;
import org.jhotdraw.app.DefaultApplicationModel;
import org.jhotdraw.app.DefaultOSXApplication;
import org.jhotdraw.app.DefaultSDIApplication;

import com.thoughtworks.studio.tools.cardkit.gui.CardkitApplicationModel;

public class CardManager {
	private static Logger logger = Logger.getLogger(CardManager.class);
	private String storyWallfilename;
	private CardRepository repository;

	public Map<Float, Card> getCards() {

		return repository.getCards();
	}


	public void run(String[] args) throws IOException {
		
		updateStoryWall();
		// start GUI
		Application app = getApplicationByPlatform();

		DefaultApplicationModel model = new CardkitApplicationModel();
		model.setName("Story Wall");
		model.setVersion("0.1");
		model
				.setCopyright("Copyright 2006-2007 (c) by Qiao Liang\n"
						+ "This software is licensed under LGPL or Creative Commons 2.5 BY");
		model
				.setProjectClassName("com.thoughtworks.studio.tools.cardkit.gui.CardkitProject");
		app.setModel(model);
		app.launch(args);
	}
	private void updateStoryWall() throws IOException {
		repository.getCards();
		if (!new File(storyWallfilename).exists()
				|| !isFormat(storyWallfilename)) {
			createFileForStoryWall();
		}
		try {

			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(storyWallfilename);
			Element root = doc.getRootElement();
			Element figures = root.getChild("figures");
			Element newfigures = updateCardNode(figures);
			List dependencies = figures.getChildren("dep");
			Object[] array = dependencies.toArray();
			for (int i =0; i<array.length;i++) {
				Element el = (Element) array[i];
				newfigures.addContent(el.detach());
			}
			Element newroot = new Element("PertDiagram");
			newroot.addContent(newfigures);
			writeToXML(new Document(newroot));

		} catch (JDOMException e) {
			logger.error("updatestorywall() failed!");
			e.printStackTrace();
		}
	}

	private void detechDependencies(List<Element> dependencies) {

		for (int i = 0; i < dependencies.size(); i++) {
			Element el = dependencies.get(i);
			el.detach();
			System.out.println(i);
		}
	}

	private void attachDependencies(Element figures, List dependencies) {
		for (int i = 0; i <= dependencies.size(); i++) {
			Element el = (Element) dependencies.get(i);
			figures.addContent(el.detach());
		}

	}

	/**
	 * @param doc
	 * @throws IOException
	 */
	private void writeToXML(Document doc) throws IOException {
		Format format = Format.getCompactFormat();
		XMLOutputter outputter = new XMLOutputter(format);
		FileWriter writer = new FileWriter(storyWallfilename);
		outputter.output(doc, writer);
		writer.close();
	}

	private boolean isFormat(String storyWallfilename2) {
		boolean result = true;
		try {
			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(storyWallfilename);
			Element root = doc.getRootElement();
			if (root == null
					|| !(root.getName().equalsIgnoreCase("PertDiagram"))) {
				result = false;
			}
		} catch (Exception e) {
			result = false;
		}
		return result;
	}

	/**
	 * 
	 */
	public Document createFileForStoryWall() {
		Document doc = null;
		try {
			Element root = new Element("PertDiagram").addContent(new Element(
					"figures").addContent(""));
			doc = new Document(root);

			writeToXML(doc);
		} catch (IOException e) {
			logger.error("can not output a empty story wall file");
			e.printStackTrace();
		}
		return doc;
	}

	public Element isExisted(Card card, Element figures) {
		Element result = null;
		List<Element> cardsinxml = figures.getChildren("card");
		for (Iterator iterator = cardsinxml.iterator(); iterator.hasNext();) {
			Element cardEL = (Element) iterator.next();
			if (card.getNumber().toString().equalsIgnoreCase(
					cardEL.getChild("model").getChild("name").getChildText(
							"string"))) {
				result = cardEL;
				break;
			}
		}
		return result;
	}

	/**
	 * @param cards
	 */
	public Element updateCardNode(Element figures) {
		Element newfigures = new Element("figures");
		TreeMap<Float,Card> cards = (TreeMap<Float, Card>) repository.getCards();

		Float key = null;
		Card card = null;
		for (Iterator<Float> iterator = cards.keySet().iterator(); iterator
				.hasNext();) {
			key = iterator.next();
			card = cards.get(key);
			Element node = isExisted(card, figures);
			if (node != null) {
				newfigures.addContent(updateNode(node, card));
			} else {
				newfigures.addContent(addNode(figures, card, UUID.randomUUID()
						.toString()));
			}
		}
		figures.detach();
		return newfigures;
	}

	public Element updateNode(Element node, Card card) {
		Element s1 = node.getChild("model");
		s1 = s1.getChild("name");
		s1 = s1.getChild("string");
		s1.setText(card.getNumber().toString());
		node.getChild("model").getChild("duration").getChild("string").setText(
				card.getName());
		node.detach();
		return node;
	}

	public Element addNode(Element figures, Card card, String id) {
		Element cardnode = new Element("card").addContent(new Element("model")
				.addContent(new Element("name")
						.addContent(new Element("string").addContent(card
								.getNumber().toString()))));
		cardnode.getChild("model").addContent(
				new Element("duration").addContent(new Element("string")
						.addContent(card.getName())));
		cardnode.setAttribute("id", id);
		cardnode.setAttribute("X", "0");
		cardnode.setAttribute("Y", "0");
		return cardnode;
	}

	/**
	 * @return
	 */
	private Application getApplicationByPlatform() {
		Application app;
		String os = System.getProperty("os.name").toLowerCase();
		if (os.startsWith("mac")) {
			app = new DefaultOSXApplication();
		} else if (os.startsWith("win")) {
			app = new DefaultSDIApplication();
		} else {
			app = new DefaultSDIApplication();
		}
		return app;
	}


	public String getStoryWallfilename() {
		return storyWallfilename;
	}

	public void setStoryWallfilename(String storyWallfilename) {
		this.storyWallfilename = storyWallfilename;
	}


	public CardRepository getRepository() {
		return repository;
	}


	public void setRepository(CardRepository repository) {
		this.repository = repository;
	}
}
